package threadjuc;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * @author zxl
 * @version 1.0
 * @date 2021/10/29 14:00
 * CAS,compare and swap的缩写，中文翻译成比较并交换。
 */
public class Juc16 {
    /**
     * 比较当前工作内存的值和主内存的值，如果是期望的值，则替换，如果不是就循环
     * CAS 操作包含三个操作数 —— 内存位置（V）、预期原值（A）和新值(B)
     * 通常将 CAS 用于同步的方式是从地址 V 读取值 A，执行多步计算来获得新 值 B，然后使用 CAS 将 V 的值从 A 改为 B。如果 V 处的值尚未同时更改，则 CAS 操作成功
     * CAS仍然存在三大问题。ABA问题，循环时间长开销大和只能保证一个共享变量的原子操作
     * https://blog.csdn.net/ls5718/article/details/52563959
     */

    public static void main(String[] args) {
        //预期值
        AtomicInteger atomicInteger = new AtomicInteger(200);
        System.out.println(atomicInteger.compareAndSet(200, 201));
        System.out.println(atomicInteger.get());

        System.out.println(atomicInteger.compareAndSet(200, 202));
        System.out.println(atomicInteger.get());


        System.out.println("================================");

        //解决ABA问题 ， 相当于乐观锁   注意Integer的默认范围是-127到128   一般都是对象
        AtomicStampedReference<Integer> stampedReference = new AtomicStampedReference(12,1);

        new Thread(()->{
            //获得时间戳 相当于乐观锁的version
            int stamp = stampedReference.getStamp();
            System.out.println("a:"+stamp);
            try {
                TimeUnit.SECONDS.sleep(2);
                System.out.println(stampedReference.compareAndSet(12, 13, stamp, stamp + 1));
                stamp = stampedReference.getStamp();
                System.out.println("a:"+stamp);
                System.out.println(stampedReference.compareAndSet(13, 12, stamp, stamp + 1));
                System.out.println("a:"+stampedReference.getStamp());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }


        },"a").start();

        new Thread(()->{
            int stamp = stampedReference.getStamp();
            System.out.println("b:"+ stamp);
            try {
                TimeUnit.SECONDS.sleep(3);
                System.out.println(stampedReference.compareAndSet(12, 14, stamp, stamp + 1));
                System.out.println("b:"+stampedReference.getStamp());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        },"b").start();
    }
}
